/*
 * Command.cpp
 *
 *  Created on: 2012-12-27
 *      Author: yangentao@gmail.com
 */

#include <assert.h>
#include "Task.h"

using namespace std;
namespace ftp {
using namespace yet;

Task::Task() :
		Super() {
	init();
}

Task::Task(FtpContext* c) :
		Super(c) {
	init();
}
Task::~Task() {
}
void Task::init() {
	cmd = FTP_NONE;
}
bool Task::execute() {
	assert(packet->cmd != FTP_NONE);
	assert(context);
	return processCommand(packet.get());
}
void Task::connect(string host, u_short port) {
	context->host = host;
	context->port = port;
	stopOnFailed = true;
	packet.reset(new Packet());
	packet->CONNECT();
}

void Task::login(string username, string password, string account) {
	assert(!username.empty());
	stopOnFailed = true;
	packet.reset(new Packet());
	packet->USER(username);
	if (!password.empty()) {
		packet->nextPacket.reset(new Packet());
		packet->nextPacket->PASS(password);
		if (!account.empty()) {
			packet->nextPacket->nextPacket.reset(new Packet());
			packet->nextPacket->nextPacket->ACCT(account);
		}
	}
}
void Task::rename(string from, string to) {
	assert(!from.empty());
	assert(!to.empty());
	packet.reset(new Packet());
	packet->RNFR(from);
	packet->nextPacket.reset(new Packet());
	packet->nextPacket->RNTO(to);
}
void Task::rest(string maker) {
	assert(!maker.empty());
	packet.reset(new Packet());
	packet->REST(maker);
}
void Task::acct(string account) {
	assert(!account.empty());
	packet.reset(new Packet());
	packet->ACCT(account);
}
void Task::cwd(string pathname) {
	packet.reset(new Packet());
	packet->CWD(pathname);
}
void Task::cdup() {
	packet.reset(new Packet());
	packet->CDUP();
}
void Task::smnt(string pathname) {
	packet.reset(new Packet());
	packet->SMNT(pathname);
}
void Task::quit() {
	packet.reset(new Packet());
	packet->QUIT();
}
void Task::rein() {
	packet.reset(new Packet());
	packet->REIN();
}
void Task::port(string host, short port) {
	packet.reset(new Packet());
	packet->PORT(host, port);
}
void Task::pasv() {
	packet.reset(new Packet());
	packet->PASV();
}
void Task::type(string type) {
	packet.reset(new Packet());
	packet->TYPE(type);
}
void Task::stru(string stru) {
	packet.reset(new Packet());
	packet->STRU(stru);
}
void Task::mode(string mode) {
	packet.reset(new Packet());
	packet->MODE(mode);
}
void Task::stor(string pathname) {
	packet.reset(new Packet());
	packet->STOR(pathname);
}
void Task::stou() {
	packet.reset(new Packet());
	packet->STOU();
}
void Task::appe(string pathname) {
	packet.reset(new Packet());
	packet->APPE(pathname);
}
void Task::allo(string n, string n2) {
	packet.reset(new Packet());
	packet->ALLO(n, n2);
}
void Task::abor() {
	packet.reset(new Packet());
	packet->ABOR();
}
void Task::dele(string pathname) {
	packet.reset(new Packet());
	packet->DELE(pathname);
}
void Task::rmd(string pathname) {
	packet.reset(new Packet());
	packet->RMD(pathname);
}
void Task::mkd(string pathname) {
	packet.reset(new Packet());
	packet->MKD(pathname);
}
void Task::pwd() {
	packet.reset(new Packet());
	packet->PWD();
}
//type A
//pasv
//connect
//list
void Task::list(string pathname) {
	packet.reset(new Packet());
	packet->LIST(pathname);
}
void Task::nlst(string pathname) {
	packet.reset(new Packet());
	packet->NLST(pathname);
}
void Task::site(string s) {
	packet.reset(new Packet());
	packet->SITE(s);
}
void Task::syst() {
	packet.reset(new Packet());
	packet->SYST();
}
void Task::stat(string pathname) {
	packet.reset(new Packet());
	packet->STAT(pathname);
}
void Task::help(string s) {
	packet.reset(new Packet());
	packet->HELP(s);
}
void Task::noop() {
	packet.reset(new Packet());
	packet->NOOP();
}

void Task::feat() {
	packet.reset(new Packet());
	packet->FEAT();
}
void Task::saveData(Packet* packet) {
	//isNext:  user/rnfr/rest
	if (packet->isNext()) {
		return;
	}
	if (!packet->isOk()) {
		return;
	}
	//is ok
	switch (packet->cmd) {
	case FTP_CONNECT: {
		string line = packet->firstLine();
		context->connectResponse = line.substr(4);
		break;
	}
	case FTP_PWD: {
		string line = packet->firstLine();
		if (line.length() > 5) {
			line = line.substr(5, line.length() - 6);
			context->pwd = line;
		}
		break;
	}
	case FTP_HELP: {
		context->serverCommands.clear();
		if (packet->responseCount() > 0) {
			vector<string> lines = packet->getLines(0);
			if (lines.size() > 2) {
				for (size_t i = 1; i < lines.size() - 1; ++i) {
					string line = lines[i];
					vector<string> words = split(line, ' ');
					for (size_t w = 0; w < words.size(); ++w) {
						string word = trim(words[w]);
						if (!word.empty()) {
							context->serverCommands.insert(word);
						}
					}
				}
			}
		}
		break;
	}
	case FTP_PASV: {
		string line = packet->firstLine();
		string::size_type n = line.find('(');
		if (n != string::npos) {
			string::size_type n2 = line.find(')', n);
			if (n2 != string::npos && n2 > n + 1 && n + 1 < line.size()) {
				string ftpaddr = line.substr(n + 1, n2 - n - 1);
				cout << ftpaddr << endl;
				context->pasvIP = getIpByFtpAddr(ftpaddr);
				context->pasvPort = getPortByFtpAddr(ftpaddr);
				if (context->pasvSock.createTcpSocket()) {
					if (context->pasvSock.connect(context->pasvIP, context->pasvPort)) {
						return;
					}
				}
			}
		}
		break;
	}

	case FTP_LIST: {
		int n = 0;
		AutoBuffer<char> buf(256);
		while(true){
			n = context->pasvSock.recv(buf.buffer, buf.length);
			if(n > 0){
				context->listData.append(buf.buffer, n);
			}else if(n == 0){
				context->listDataOK = true;
				context->pasvSock.close();
				cout<<context->listData<<endl;
				break;
			}else{
				context->listDataOK = false;
				SocketError e;
				ftplog<<err<<e.getCode()<<" "<<e.getCodeName()<<end;
				context->pasvSock.close();
			}
		}
		break;
	}
	case FTP_NLST: {
		int n = 0;
		AutoBuffer<char> buf(256);
		while(true){
			n = context->pasvSock.recv(buf.buffer, buf.length);
			if(n > 0){
				context->nlstData.append(buf.buffer, n);
			}else if(n == 0){
				context->nlstDataOK = true;
				context->pasvSock.close();
				break;
			}else{
				context->nlstDataOK = false;
				SocketError e;
				ftplog<<err<<e.getCode()<<" "<<e.getCodeName()<<end;
				context->pasvSock.close();
			}
		}
		break;
	}
	}
}
bool Task::processCommand(Packet* p) {
	if (p->cmd == FTP_CONNECT) {
		if (!context->connect()) {
			return false;
		}
		if (!context->recvControl(p)) {
			context->sock.close();
			return false;
		}
	} else {
		if (!context->sendRecvControl(p)) {
			return false;
		}
	}
	saveData(p);
	if (packet->cmd == FTP_QUIT) {
		context->sock.close();
	}
	if (p->nextPacket) {
		return processCommand(p->nextPacket.get());
	}
	return true;
}

} /* namespace yet */
